package indi.zhifa.recipe.bailan.framework.auth.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import indi.zhifa.recipe.bailan.framework.auth.dao.IBaseAuthNodeRelevantDao;
import indi.zhifa.recipe.bailan.framework.auth.dao.IBaseUserRelevantDao;
import indi.zhifa.recipe.bailan.framework.auth.entity.BaseTokenObject;
import indi.zhifa.recipe.bailan.framework.auth.entity.dto.user.ChangePasswdDto;
import indi.zhifa.recipe.bailan.framework.auth.entity.po.*;
import indi.zhifa.recipe.bailan.framework.auth.entity.vo.BaseDomainVo;
import indi.zhifa.recipe.bailan.framework.auth.property.DepartmentConfig;
import indi.zhifa.recipe.bailan.framework.auth.property.PasswdConfig;
import indi.zhifa.recipe.bailan.framework.auth.property.UserConfig;
import indi.zhifa.recipe.bailan.framework.auth.service.IBaseUserService;
import indi.zhifa.recipe.bailan.framework.auth.util.IBaseTokenUtil;
import indi.zhifa.recipe.bailan.framework.common.entity.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
public abstract class BaseUserServiceImpl implements IBaseUserService {

    protected final IBaseUserRelevantDao mUserRelevantDao;
    protected final IBaseAuthNodeRelevantDao mDepartmentRelevantDao;
    protected final UserConfig mUserConfig;
    protected final PasswordEncoder mPasswordEncoder;

    protected final IBaseTokenUtil mBaseTokenUtil;

    protected LocalDateTime getExpireTime() {
        PasswdConfig passwdConfig = mUserConfig.getPasswd();
        return LocalDateTime.now().plusDays(passwdConfig.getExpireDay());
    }

    protected BaseUserEntity _createUser(BaseUserEntity pBaseUserEntity, List<String> pRoles, Map<String,String> pIniDeps) {
        if (mUserRelevantDao.user_existByName(pBaseUserEntity.getName())) {
            throw new ServiceException("已经存在名为" + pBaseUserEntity.getName() + "的用户");
        }
        PasswdConfig passwdConfig = mUserConfig.getPasswd();
        BaseUserEntity userEntity = pBaseUserEntity;

        if (StringUtils.hasText(pBaseUserEntity.getPassword())) {
            userEntity.setPassword(mPasswordEncoder.encode(pBaseUserEntity.getPassword()));
            userEntity.setExpireTime(getExpireTime());
        } else {
            userEntity.setPassword(mPasswordEncoder.encode(passwdConfig.getDefaultPasswd()));
            userEntity.setExpireTime(LocalDateTime.now());
        }
        userEntity.setBan(false);
        userEntity = mUserRelevantDao.user_save(userEntity);

        // 处理初始的用户角色
        List<BaseRelUserRoleEntity> baseRelUserRoleEntityList = new ArrayList<>();

        if (CollectionUtils.isEmpty(pRoles)) {
            pRoles = mUserConfig.getDefaultRole();
        }

        for (String roleCode : pRoles) {
            BaseRelUserRoleEntity baseRelUserRoleEntity = mUserRelevantDao.relUserRole_generate();
            baseRelUserRoleEntity.createInit();
            baseRelUserRoleEntity.setUserId(userEntity.getId());
            baseRelUserRoleEntity.setUserName(userEntity.getName());
            BaseRoleEntity baseRoleEntity = null;
            baseRoleEntity = mUserRelevantDao.role_check(roleCode);
            baseRelUserRoleEntity.setRoleId(baseRoleEntity.getId());
            baseRelUserRoleEntity.setRoleCode(baseRoleEntity.getCode());
            baseRelUserRoleEntityList.add(baseRelUserRoleEntity);
        }
        mUserRelevantDao.relUserRole_updateRoles(userEntity.getId(), baseRelUserRoleEntityList);

        // 设置初始的部门
        List<BaseRelUserAuthEntity> savingRelUserDepEntity = new ArrayList<>();
        List<DepartmentConfig> defaultDepartmentConfigList = null;

        if(null != pIniDeps){
            defaultDepartmentConfigList = pIniDeps.entrySet().stream().map(entry->{
                DepartmentConfig departmentConfig = new DepartmentConfig();
                departmentConfig.setDomain(entry.getKey());
                departmentConfig.setDepCode(entry.getValue());
                return departmentConfig;
            }).collect(Collectors.toList());
        }else{
            defaultDepartmentConfigList = mUserConfig.getDefaultDepartments();
        }

        for (int i = 0; i < defaultDepartmentConfigList.size(); i++) {
            DepartmentConfig departmentConfig = defaultDepartmentConfigList.get(i);
            BaseRelUserAuthEntity baseRelUserAuthEntity = mDepartmentRelevantDao.relUserAuth_generate();
            baseRelUserAuthEntity.createInit();
            baseRelUserAuthEntity.setUserId(userEntity.getId());
            baseRelUserAuthEntity.setUserName(userEntity.getName());
            baseRelUserAuthEntity.setDomainCode(departmentConfig.getDomain());
            BaseDomainVo baseDomainVo = null;
            BaseDomainEntity domainEntity  = mDepartmentRelevantDao.domain_check(departmentConfig.getDomain());
            baseRelUserAuthEntity.setDomainId(domainEntity.getId());
            String depCode = departmentConfig.getDepCode();
            BaseAuthNodeEntity departmentEntity = null;
            if(null != baseDomainVo){
                departmentEntity = baseDomainVo.checkDepartment(depCode);
            }else{
                departmentEntity = mDepartmentRelevantDao.authNode_check(domainEntity.getId(), depCode);
            }
            baseRelUserAuthEntity.setAuthId(departmentEntity.getId());
            baseRelUserAuthEntity.setAuthCode(departmentEntity.getCode());
            baseRelUserAuthEntity.setAuthCascade(departmentEntity.getCascade());
            savingRelUserDepEntity.add(baseRelUserAuthEntity);
        }
        mDepartmentRelevantDao.relUserAuth_saveBatch(userEntity.getId(), savingRelUserDepEntity);
        return userEntity;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseUserEntity createUser(BaseUserEntity pBaseUserEntity, List<String> pRoles, Map<String,String> pIniDeps) {
        return _createUser(pBaseUserEntity, pRoles, pIniDeps);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseUserEntity changePasswdByUser(ChangePasswdDto pChangePasswdDto) {

        BaseTokenObject baseTokenObject = mBaseTokenUtil.getTokenObject();
        Long userId = baseTokenObject.getId();
        BaseUserEntity baseUserEntity = mUserRelevantDao.user_check(userId);
        if (!mPasswordEncoder.matches(pChangePasswdDto.getOrgPasswd(), baseUserEntity.getPassword())) {
            throw new ServiceException("密码不正确");
        }
        String newPasswd = mPasswordEncoder.encode(pChangePasswdDto.getNewPasswd());

        BaseUserEntity editingUserEntity = mUserRelevantDao.user_generate();
        editingUserEntity.updateInit();
        editingUserEntity.setId(baseUserEntity.getId());
        editingUserEntity.setPassword(newPasswd);
        editingUserEntity.setExpireTime(getExpireTime());

        mUserRelevantDao.user_edit(editingUserEntity.getId(), editingUserEntity);
        return baseUserEntity;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseUserEntity resetPasswd(Long pUserId) {
        BaseUserEntity userEntity = mUserRelevantDao.user_check(pUserId);
        PasswdConfig passwdConfig = mUserConfig.getPasswd();
        String encodePasswd = mPasswordEncoder.encode(passwdConfig.getDefaultPasswd());

        BaseUserEntity editingUserEntity = mUserRelevantDao.user_generate();
        editingUserEntity.updateInit();
        editingUserEntity.setId(pUserId);
        editingUserEntity.setPassword(encodePasswd);
        editingUserEntity.setExpireTime(LocalDateTime.now());
        mUserRelevantDao.user_edit(editingUserEntity.getId(), editingUserEntity);
        return userEntity;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseUserEntity setActive(Long pUserId, boolean pActive) {
        BaseUserEntity userEntity = mUserRelevantDao.user_check(pUserId);
        BaseUserEntity editingUserEntity = mUserRelevantDao.user_generate();
        editingUserEntity.updateInit();
        editingUserEntity.setBan(!pActive);
        mUserRelevantDao.user_edit(editingUserEntity.getId(), editingUserEntity);
        return userEntity;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeUser(Long pUserId) {
        mUserRelevantDao.user_removeById(pUserId);
        return true;
    }

    protected List<String> getUserRoles(Long pUserId) {
        List<BaseRelUserRoleEntity> roleCodes = mUserRelevantDao.relUserRole_listByUserId(pUserId);
        if (CollectionUtils.isEmpty(roleCodes)) {
            return new ArrayList<>();
        }
        return roleCodes.stream().map(BaseRelUserRoleEntity::getRoleCode).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<String, BaseRoleEntity> initRole(JSONArray pDefaultRolesCfg) {
        Map<String, BaseRoleEntity> rtn = new HashMap<>();
        for (int i = 0; i < pDefaultRolesCfg.size(); i++) {
            JSONObject roleJsonCfg = pDefaultRolesCfg.getJSONObject(i);
            BaseRoleEntity baseRoleEntity = mUserRelevantDao.role_load(roleJsonCfg);
            if (!mUserRelevantDao.role_existByCode(baseRoleEntity.getCode())) {
                mUserRelevantDao.role_save(baseRoleEntity);
            }
            rtn.put(baseRoleEntity.getCode(), baseRoleEntity);
        }
        return rtn;
    }



    @Transactional(rollbackFor = Exception.class)
    public List<BaseUserEntity> initUser(JSONArray pDefaultUserCfg) {
        List<BaseUserEntity> userEntityList = new ArrayList<>();
        for (int i = 0; i < pDefaultUserCfg.size(); i++) {
            JSONObject userJsonCfg = pDefaultUserCfg.getJSONObject(i);
            List<String> roles = userJsonCfg.getList("roles", String.class);
            Map<String,String> deps = (Map<String,String>)userJsonCfg.get("departments");
            BaseUserEntity baseUserEntity = mUserRelevantDao.user_load(userJsonCfg);
            if (!mUserRelevantDao.user_existByName(baseUserEntity.getName())) {
                baseUserEntity = _createUser(baseUserEntity, roles, deps);
            }
            userEntityList.add(baseUserEntity);
        }
        return userEntityList;
    }


}
